/**
 * @Description: 数字格式化（金额等）指令
 * @Author 卞鹏飞 <228443632@qq.com>
 * @create 2023/1/31 20:05
 * @example
 * v-input-num
 * v-input-num={format: '0,0', digit: 2}  // 自定义格式化
 */
import numeral from 'numeral'
import { def, isSyncFunction, hasOwn } from 'sf-utils2'

/**
 * 格式化金钱
 * @param {string} money
 * @param {string} format
 * @return {*|string}
 */
export function formatMoney(money, format = '0,00.00') {
  return (money || 0) === 0 ? '0.00' : money ? numeral(money).format(format) : ''
}

/**
 * 格式化input框对象
 * @param {HTMLElement|Node} inputDOM
 */
function inputNumEvent(inputDOM) {
  const numEvent = {
    inputDOM,
    props: {
      disabled: false, // 是否禁止格式化， 默认是开启
      format: '0,0', // 格式化
      formatter: undefined, // 格式化方法
      digit: 2 // 保留的小数位数
    },

    /**
     * 合并props
     * @param {Object} val
     */
    mergeProps(val = {}) {
      Object.keys(this.props).forEach((key) => hasOwn(val, key) && (this.props[key] = val[key]))
    },

    /**
     * 聚焦
     */
    focus() {
      if (this.inputDOM.disabled || this.inputDOM.readonly) return
      const value = this.inputDOM.value
      // 支持双向绑定
      this.inputDOM.value = value ? numeral(value).format(this._oFormat) : ''
      this._modelValue = value
    },

    /**
     * 失去焦点
     */
    blur(lifeType) {
      const value = this.inputDOM.value
      // 支持双向绑定
      lifeType != '@init' && (this._modelValue = value)
      if (isSyncFunction(this.formatter)) {
        this.inputDOM.value = this.formatter(value)
      } else {
        this.inputDOM.value = value ? numeral(value).format(this._format) : ''
      }
    }
  }

  Object.defineProperties(numEvent, {
    // 失去焦点的格式化
    _format: {
      configurable: false,
      get() {
        const props = numEvent.props
        let format = props.format
        if (props.format === '0,0') {
          const dot = props.digit > 0 ? `.${''.padStart(2, '0')}` : ''
          format = `${props.format}${dot}`
        }
        return format
      }
    },
    _oFormat: {
      configurable: false,
      get() {
        return this._format?.replace?.(/^0|,/g, '')
      }
    },

    _modelValue: {
      get() {
        return this.inputDOM.value
      },
      set(val) {
        this.inputDOM.value = val ? numeral(val).format(this._oFormat) : ''
        this.inputDOM.dispatchEvent(new Event('input'))
      }
    }
  })

  return numEvent
}

export default {
  mounted(el, binding) {
    const inputDOM = el?.tagName == 'INPUT' ? el : el?.querySelector?.('input')
    if (!inputDOM) return
    if (binding?.value?.disabled) return
    const numEvent = inputNumEvent(inputDOM)
    numEvent.mergeProps(binding?.value || {}, el, inputDOM)
    el._inputNumEvent = numEvent
    def(el, '_inputNumEvent')
    numEvent._focus = Function.prototype.bind.call(numEvent.focus, numEvent)
    numEvent._blur = Function.prototype.bind.call(numEvent.blur, numEvent)
    inputDOM.addEventListener('focus', numEvent._focus)
    inputDOM.addEventListener('blur', numEvent._blur)
    numEvent.blur('@init')
  },

  /**
   * 更新阶段
   * @param el
   * @param binding
   */
  updated(el, binding) {
    if (binding.value?.disabled) return
    // if (looseEqual(binding.oldValue, binding.value)) return
    const numEvent = el._inputNumEvent
    if (numEvent?.inputDOM) {
      numEvent.mergeProps(binding?.value || {})
      if (document.activeElement !== numEvent.inputDOM) {
        numEvent._blur()
      }
    }
  },

  /**
   * 卸载阶段
   * @param el
   */
  unmounted(el) {
    const numEvent = el._inputNumEvent
    if (numEvent?.inputDOM) {
      numEvent.inputDOM.addEventListener('focus', numEvent._focus)
      numEvent.inputDOM.addEventListener('blur', numEvent._blur)
    }
  }
}
